/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007-2008 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.web.gwt.basics.client;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.genia.toolbox.web.gwt.basics.client.i18n.GwtI18nMessage;
import com.genia.toolbox.web.gwt.basics.client.i18n.I18nCallBack;
import com.google.gwt.user.client.rpc.AsyncCallback;

/**
 * A timer that handle i18n batching.
 */
public class I18nAggregator
    implements AsyncCallback<List<String>>
{

  /**
   * the singleton instance of the timer.
   */
  private static I18nAggregator instance = null;



  /**
   * private constructor.
   */
  private I18nAggregator()
  {
    // Do nothing.
  }

  /**
   * the messages currently begin translated.
   */
  private List<GwtI18nMessage> sentMessages = null;

  /**
   * the callbacks for the messages being translated.
   */
  private List<List<I18nCallBack>> callbacks = null;

  /**
   * the messages that are queued to be translated.
   */
  private final Map<GwtI18nMessage, List<I18nCallBack>> requests = new HashMap<GwtI18nMessage, List<I18nCallBack>>();



  /**
   * the public method that queue a message for translation.
   * 
   * @param gwtI18nMessage
   *          the message to translate
   * @param i18nCallBack
   *          the callback for the message
   */
  public static synchronized void translate(final GwtI18nMessage gwtI18nMessage, final I18nCallBack i18nCallBack)
  {
    if (instance == null) {
      instance = new I18nAggregator();
    }
    instance.queueTranslation(gwtI18nMessage, i18nCallBack);
    instance.run();
  }



  /**
   * this method queue a message for translation.
   * 
   * @param gwtI18nMessage
   *          the message to translate
   * @param i18nCallBack
   *          the callback for the message
   */
  private synchronized void queueTranslation(final GwtI18nMessage gwtI18nMessage, final I18nCallBack i18nCallBack)
  {
    List<I18nCallBack> callbacks = requests.get(gwtI18nMessage);
    if (callbacks == null) {
      callbacks = new ArrayList<I18nCallBack>();
      requests.put(gwtI18nMessage, callbacks);
    }
    callbacks.add(i18nCallBack);
  }



  /**
   * the periodic method that check if there is message to translate and act
   * accordingly.
   * 
   * @see com.google.gwt.user.client.Command#execute()
   */
  synchronized public void run()
  {
    if (requests.isEmpty() || sentMessages != null) {
      return;
    }
    sentMessages = new ArrayList<GwtI18nMessage>();
    callbacks = new ArrayList<List<I18nCallBack>>();
    for (final Entry<GwtI18nMessage, List<I18nCallBack>> entry : requests.entrySet()) {
      sentMessages.add(entry.getKey());
      callbacks.add(entry.getValue());
    }
    requests.clear();
    GwtHelper.getI18nService().getMessage(sentMessages, this);
  }



  /**
   * returns the default translation for a message that can not be translated.
   * 
   * @param i18nMessage
   *          the message to translate
   * @return a default translation
   */
  private String getDefaultValue(GwtI18nMessage i18nMessage)
  {
    String message = "{ " + i18nMessage.getKey();
    for (int i = 0; i < i18nMessage.getParameters().length; i++) {
      message += " : " + i18nMessage.getParameters()[i];
    }
    message += " }";
    return message;
  }



  /**
   * called if there is an error with the RPC call. That should not happen.
   * 
   * @param caught
   *          the error
   * @see com.google.gwt.user.client.rpc.AsyncCallback#onFailure(java.lang.Throwable)
   */
  synchronized public void onFailure(Throwable caught)
  {
    // Can't happen.
    try {
      callbacks = null;
      sentMessages = null;
      GwtHelper.logger.error(caught.getMessage());
    }
    finally {
      run();
    }
  }



  /**
   * called when the current translation is done.
   * 
   * @param result
   *          the list of translated messages
   * @see com.google.gwt.user.client.rpc.AsyncCallback#onSuccess(java.lang.Object)
   */
  synchronized public void onSuccess(List<String> result)
  {
    try {
      Iterator<List<I18nCallBack>> i18nCallbacksIterator = callbacks.iterator();
      Iterator<GwtI18nMessage> gwtI18nMessageIterator = sentMessages.iterator();
      Iterator<String> resultIterator = result.iterator();
      callbacks = null;
      sentMessages = null;
      while (i18nCallbacksIterator.hasNext()) {
        final GwtI18nMessage i18nMessage = gwtI18nMessageIterator.next();
        final String resultValue = resultIterator.next();
        for (final I18nCallBack callBack : i18nCallbacksIterator.next()) {
          if (resultValue == null) {
            callBack.getMessage(getDefaultValue(i18nMessage));
          }
          else {
            callBack.getMessage(resultValue);
          }
        }
      }
    }
    finally {
      run();
    }
  }

}
